/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    FsRtlP.c

Abstract:

    This module declares the global data used by the FsRtl Module

--*/

#include "FsRtlP.h"

#define COMPATIBILITY_MODE_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
#define COMPATIBILITY_MODE_VALUE_NAME L"Win95TruncatedExtensions"

#define KEY_WORK_AREA ((sizeof(KEY_VALUE_FULL_INFORMATION) + \
                        sizeof(ULONG)) + 64)

#ifdef FSRTLDBG

LONG FsRtlDebugTraceLevel = 0x0000000f;
LONG FsRtlDebugTraceIndent = 0;

#endif // FSRTLDBG

//
//  Local Support routine
//

NTSTATUS
FsRtlGetCompatibilityModeValue (
    IN PUNICODE_STRING ValueName,
    IN OUT PULONG Value
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FsRtlAllocateResource)
#pragma alloc_text(INIT, FsRtlInitSystem)
#pragma alloc_text(INIT, FsRtlGetCompatibilityModeValue)
#endif

//
//  Define the number of resources, a pointer to them and a counter for
//  resource selection.
//

#define FSRTL_NUMBER_OF_RESOURCES (16)

PERESOURCE FsRtlPagingIoResources;

#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
ULONG FsRtlPagingIoResourceSelector = 0;
BOOLEAN FsRtlSafeExtensions = TRUE;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif

//
//  The global static legal ANSI character array.  Wild characters
//  are not considered legal, they should be checked separately if
//  allowed.
//

#define _FAT_  FSRTL_FAT_LEGAL
#define _HPFS_ FSRTL_HPFS_LEGAL
#define _NTFS_ FSRTL_NTFS_LEGAL
#define _OLE_  FSRTL_OLE_LEGAL
#define _WILD_ FSRTL_WILD_CHARACTER

static const UCHAR LocalLegalAnsiCharacterArray[128] = {

    0                                   ,   // 0x00 ^@
                                   _OLE_,   // 0x01 ^A
                                   _OLE_,   // 0x02 ^B
                                   _OLE_,   // 0x03 ^C
                                   _OLE_,   // 0x04 ^D
                                   _OLE_,   // 0x05 ^E
                                   _OLE_,   // 0x06 ^F
                                   _OLE_,   // 0x07 ^G
                                   _OLE_,   // 0x08 ^H
                                   _OLE_,   // 0x09 ^I
                                   _OLE_,   // 0x0A ^J
                                   _OLE_,   // 0x0B ^K
                                   _OLE_,   // 0x0C ^L
                                   _OLE_,   // 0x0D ^M
                                   _OLE_,   // 0x0E ^N
                                   _OLE_,   // 0x0F ^O
                                   _OLE_,   // 0x10 ^P
                                   _OLE_,   // 0x11 ^Q
                                   _OLE_,   // 0x12 ^R
                                   _OLE_,   // 0x13 ^S
                                   _OLE_,   // 0x14 ^T
                                   _OLE_,   // 0x15 ^U
                                   _OLE_,   // 0x16 ^V
                                   _OLE_,   // 0x17 ^W
                                   _OLE_,   // 0x18 ^X
                                   _OLE_,   // 0x19 ^Y
                                   _OLE_,   // 0x1A ^Z
                                   _OLE_,   // 0x1B ESC
                                   _OLE_,   // 0x1C FS
                                   _OLE_,   // 0x1D GS
                                   _OLE_,   // 0x1E RS
                                   _OLE_,   // 0x1F US
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x20 space
    _FAT_ | _HPFS_ | _NTFS_              ,  // 0x21 !
                            _WILD_| _OLE_,  // 0x22 "
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x23 #
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x24 $
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x25 %
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x26 &
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x27 '
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x28 (
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x29 )
                            _WILD_| _OLE_,  // 0x2A *
            _HPFS_ | _NTFS_       | _OLE_,  // 0x2B +
            _HPFS_ | _NTFS_       | _OLE_,  // 0x2C ,
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x2D -
    _FAT_ | _HPFS_ | _NTFS_              ,  // 0x2E .
    0                                    ,  // 0x2F /
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x30 0
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x31 1
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x32 2
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x33 3
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x34 4
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x35 5
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x36 6
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x37 7
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x38 8
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x39 9
                     _NTFS_              ,  // 0x3A :
            _HPFS_ | _NTFS_       | _OLE_,  // 0x3B ;
                            _WILD_| _OLE_,  // 0x3C <
            _HPFS_ | _NTFS_       | _OLE_,  // 0x3D =
                            _WILD_| _OLE_,  // 0x3E >
                            _WILD_| _OLE_,  // 0x3F ?
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x40 @
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x41 A
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x42 B
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x43 C
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x44 D
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x45 E
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x46 F
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x47 G
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x48 H
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x49 I
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4A J
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4B K
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4C L
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4D M
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4E N
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x4F O
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x50 P
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x51 Q
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x52 R
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x53 S
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x54 T
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x55 U
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x56 V
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x57 W
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x58 X
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x59 Y
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x5A Z
            _HPFS_ | _NTFS_       | _OLE_,  // 0x5B [
    0                                    ,  // 0x5C backslash
            _HPFS_ | _NTFS_       | _OLE_,  // 0x5D ]
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x5E ^
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x5F _
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x60 `
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x61 a
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x62 b
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x63 c
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x64 d
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x65 e
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x66 f
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x67 g
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x68 h
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x69 i
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6A j
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6B k
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6C l
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6D m
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6E n
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x6F o
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x70 p
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x71 q
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x72 r
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x73 s
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x74 t
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x75 u
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x76 v
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x77 w
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x78 x
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x79 y
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x7A z
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x7B {
    0                             | _OLE_,  // 0x7C |
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x7D }
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x7E ~
    _FAT_ | _HPFS_ | _NTFS_       | _OLE_,  // 0x7F 
};

UCHAR const* const FsRtlLegalAnsiCharacterArray = &LocalLegalAnsiCharacterArray[0];

//
//  This routine is called during phase one initialization.
//

BOOLEAN
FsRtlInitSystem (
    )
{
    ULONG i;

    ULONG Value;
    UNICODE_STRING ValueName;

    extern KSEMAPHORE FsRtlpUncSemaphore;

    PAGED_CODE();

    //
    //  Allocate and initialize all the paging Io resources
    //

    FsRtlPagingIoResources = FsRtlAllocatePool( NonPagedPool,
                                                FSRTL_NUMBER_OF_RESOURCES *
                                                sizeof(ERESOURCE) );

    for (i=0; i < FSRTL_NUMBER_OF_RESOURCES; i++) {

        ExInitializeResourceLite( &FsRtlPagingIoResources[i] );
    }

    //
    //  Initialize the global tunneling structures.
    //

    FsRtlInitializeTunnels();

    //
    //  Initialize the global filelock structures.
    //

    FsRtlInitializeFileLocks();

    //
    //  Initialize the global largemcb structures.
    //

    FsRtlInitializeLargeMcbs();

    //
    // Initialize the semaphore used to guard loading of the MUP
    //

    KeInitializeSemaphore( &FsRtlpUncSemaphore, 1, MAXLONG );

    //
    // Pull the bit from the registry telling us whether to do a safe
    // or dangerous extension truncation.
    //

    ValueName.Buffer = COMPATIBILITY_MODE_VALUE_NAME;
    ValueName.Length = sizeof(COMPATIBILITY_MODE_VALUE_NAME) - sizeof(WCHAR);
    ValueName.MaximumLength = sizeof(COMPATIBILITY_MODE_VALUE_NAME);

    if (NT_SUCCESS(FsRtlGetCompatibilityModeValue( &ValueName, &Value )) &&
        (Value != 0)) {

        FsRtlSafeExtensions = FALSE;
    }

    //
    // Initialize the FsRtl stack overflow work QueueObject and thread.
    //

    if (!NT_SUCCESS(FsRtlInitializeWorkerThread())) {

        return FALSE;
    }

    //
    // Initialize the FsFilter component of FsRtl.
    //

    if (!NT_SUCCESS(FsFilterInit())) {

        return FALSE;
    }
    
    return TRUE;
}


PERESOURCE
FsRtlAllocateResource (
    )

/*++

Routine Description:

    This routine is used to allocate a resource from the FsRtl pool.

Arguments:

Return Value:

    PERESOURCE - A pointer to the provided resource.

--*/

{
    PAGED_CODE();

    return &FsRtlPagingIoResources[ FsRtlPagingIoResourceSelector++ %
                                    FSRTL_NUMBER_OF_RESOURCES];
}


//
//  Local Support routine
//

NTSTATUS
FsRtlGetCompatibilityModeValue (
    IN PUNICODE_STRING ValueName,
    IN OUT PULONG Value
    )

/*++

Routine Description:

    Given a unicode value name this routine will go into the registry
    location for the Chicago compatibility mode information and get the
    value.

Arguments:

    ValueName - the unicode name for the registry value located in the
                double space configuration location of the registry.
    Value   - a pointer to the ULONG for the result.

Return Value:

    NTSTATUS

    If STATUS_SUCCESSFUL is returned, the location *Value will be
    updated with the DWORD value from the registry.  If any failing
    status is returned, this value is untouched.

--*/

{
    HANDLE Handle;
    NTSTATUS Status;
    ULONG RequestLength;
    ULONG ResultLength;
    UCHAR Buffer[KEY_WORK_AREA];
    UNICODE_STRING KeyName;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PKEY_VALUE_FULL_INFORMATION KeyValueInformation;

    KeyName.Buffer = COMPATIBILITY_MODE_KEY_NAME;
    KeyName.Length = sizeof(COMPATIBILITY_MODE_KEY_NAME) - sizeof(WCHAR);
    KeyName.MaximumLength = sizeof(COMPATIBILITY_MODE_KEY_NAME);

    InitializeObjectAttributes(&ObjectAttributes,
                               &KeyName,
                               OBJ_CASE_INSENSITIVE,
                               NULL,
                               NULL);

    Status = ZwOpenKey(&Handle,
                       KEY_READ,
                       &ObjectAttributes);

    if (!NT_SUCCESS(Status)) {

        return Status;
    }

    RequestLength = KEY_WORK_AREA;

    KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;

    while (1) {

        Status = ZwQueryValueKey(Handle,
                                 ValueName,
                                 KeyValueFullInformation,
                                 KeyValueInformation,
                                 RequestLength,
                                 &ResultLength);

        ASSERT( Status != STATUS_BUFFER_OVERFLOW );

        if (Status == STATUS_BUFFER_OVERFLOW) {

            //
            // Try to get a buffer big enough.
            //

            if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {

                ExFreePool(KeyValueInformation);
            }

            RequestLength += 256;

            KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
                                  ExAllocatePoolWithTag(PagedPool,
                                                        RequestLength,
                                                        ' taF');

            if (!KeyValueInformation) {
                return STATUS_NO_MEMORY;
            }

        } else {

            break;
        }
    }

    ZwClose(Handle);

    if (NT_SUCCESS(Status)) {

        if (KeyValueInformation->DataLength != 0) {

            PULONG DataPtr;

            //
            // Return contents to the caller.
            //

            DataPtr = (PULONG)
              ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
            *Value = *DataPtr;

        } else {

            //
            // Treat as if no value was found
            //

            Status = STATUS_OBJECT_NAME_NOT_FOUND;
        }
    }

    if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {

        ExFreePool(KeyValueInformation);
    }

    return Status;
}

